package com.yihaodian.index.solr;

import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.solr.core.SolrCore;
import org.apache.solr.servlet.DirectSolrConnection;

import com.google.gson.reflect.TypeToken;
import com.yihaodian.api.common.json.GsonWrapper;
import com.yihaodian.api.index.IndexDoc;
import com.yihaodian.api.index.IndexRequest;
import com.yihaodian.index.Indexer;
import com.yihaodian.index.solr.ext.MemDataManager;
import com.yihaodian.index.solr.ext.MemDataProvider;

public class SolrIndexer implements Indexer {

	private static Logger log = Logger.getLogger(SolrIndexer.class);

	SolrIndexCommandBuilder commandBuilder = new SolrIndexCommandBuilder();
	static final Type EMF_TYPE = new TypeToken<Map<String, Map<String, Float>>>() {
	}.getType();

	DirectSolrConnection dsc = null;

	SolrCore solrCore = null;

	public SolrIndexer(SolrCore core) {
		this.solrCore = core;		
		this.dsc = new DirectSolrConnection(solrCore);
	}

	public void index(IndexRequest request) throws Exception {
		String pathAndParams = "/update"; // ?commit=true

		// If this is the external update, handle it first.
		if (handleExternalUpdate(request)) {
			return;
		}

		// handle doc update
		List<String> commands = commandBuilder.buildCommand(request);
		for (String command : commands) {
			if(log.isTraceEnabled())
				log.trace(solrCore.getName() + ", Document update: " + command);
			dsc.request(pathAndParams, command);
		}
	}

	private boolean handleExternalUpdate(IndexRequest request) {
		if (!isExternalUpdate(request)) {
			return false;
		}

		Collection<IndexDoc> docs = request.getDocs();
		if (docs != null && !docs.isEmpty()) {
			for (IndexDoc doc : docs) {
				String json = doc.getJsonDoc();
				if(log.isTraceEnabled())
					log.trace(solrCore.getName() + ", External update： " +json);
				if (json != null) {
					Map<String, Map<String, Float>> data = GsonWrapper
							.getGson().fromJson(json, EMF_TYPE);
					
					if(data == null || data.size() != 1) {
						log.error("Invalid data: " + data);
						continue;
					}
					
					String field = data.keySet().iterator().next();

					MemDataProvider dp = MemDataManager.getDataProvider(
							request.getIndexName(), field,
							solrCore.getIndexDir());
					dp.putAll(data.get(field));
				}
			}
		}

		return true;
	}

	/**
	 * Check whether it's external data update.
	 * 
	 * If there's no unique key file in the doc, then the request could not be
	 * add/update doc, assume it's external data update.
	 * 
	 * @param request
	 * @return
	 */
	private boolean isExternalUpdate(IndexRequest request) {
		String keyField = solrCore.getSchema().getUniqueKeyField().getName();

		Collection<IndexDoc> docs = request.getDocs();
		if (docs != null && !docs.isEmpty()) {			
			for (IndexDoc doc : docs) {
				if (doc.hasKeyField(keyField)) {
					return false;
				} else {
					return true;
				}
			}
		}
		return false;
	}

}
